package com.ds.api.utils;

import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

import org.apache.commons.lang.StringUtils;

/**
 * 
 * @className: XSSFilter
 * @description: TODO
 * @author yangzhiwei
 */
public class XSSFilter implements Filter {

    private static Map<Object,Object> PATTERNMAP;

    /**
     * 
     */
    public void init(FilterConfig filterconfig) throws ServletException {

        PATTERNMAP = new HashMap<Object,Object>();
        InputStream is = null;
        Properties props = new Properties();
        String propName = null;
        String propValue = null;
        Pattern p = null;

        try {
            is = XSSFilter.class.getResourceAsStream("/xssfilter.properties");
            props.load(is);
            Enumeration propKeys = props.propertyNames();
            while (propKeys.hasMoreElements()) {
                propName = (String) propKeys.nextElement();
                propValue = props.getProperty(propName);
                p = Pattern.compile(propName, Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
                PATTERNMAP.put(p, StringUtils.trimToEmpty(propValue));
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            if (is != null) {
                try {
                    is.close();
                }
                catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

    }

    /**
     * 
     */
    public void destroy() {
    }

    /**
     * 
     */
    @SuppressWarnings("unchecked")
    public void doFilter(ServletRequest servletrequest, ServletResponse servletresponse, FilterChain filterchain)
        throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) servletrequest;
        Map<String,Object> valueMap = request.getParameterMap();
        String contentType = request.getContentType();
        // System.out.println("contentType = " + contentType);
        if (contentType != null && contentType.indexOf("multipart") >= 0) {
            filterchain.doFilter(request, servletresponse);
        }
        else {
            if (valueMap != null && !valueMap.isEmpty()) {
                for (Iterator<Object> it = valueMap.values().iterator(); it.hasNext();) {
                    Object value = it.next();
                    try {
                        doClean(value);
                    }
                    catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
            filterchain.doFilter(new RequestWrapper((HttpServletRequest) request), servletresponse);
        }

    }

    /**
     * 
     * @description: TODO
     * @param value   
     * @author yangzhiwei
     * @date 2017-5-15
     */
    private void doClean(Object value) {
        if (value instanceof String[]) {
            String[] obs = (String[]) value;
            for (int i = 0; i < obs.length; i++) {
                obs[i] = cleanXSS(obs[i]);
            }
        }
    }

    /**
     * 
     * @description: TODO
     * @param s
     * @return   
     * @author yangzhiwei
     * @date 2017-5-15
     */
    private String cleanXSS(String s) {

        Set<Object> keySet = PATTERNMAP.keySet();
        Pattern p = null;
        Matcher m = null;
//        System.out.println("XSSFilter.cleanXSS() s0 = " + s);
        boolean matched = true;
        // 从Properties文件中取出来的关键字是乱序的，现在要求最先过滤掉\u0000等字符，只能每次过滤掉一个关键字后，再次完整遍历关键字列表，直到匹配不到为止
        while (matched) {
            matched = false;
            // 遍历正则表达式列表
            for (Iterator<Object> it = keySet.iterator(); it.hasNext();) {
                p = (Pattern) it.next();
                m = p.matcher(s);
                if (m.find()) {
                    matched = true;
                    s = m.replaceAll((String) PATTERNMAP.get(p));
//                    System.out.println("XSSFilter.cleanXSS() s  = " + s);
                    break;// 如果匹配到了替换后则中断，回到while的地方，从头开始便利正则表达式，直到遍历全部了全部正则表达式都没有匹配项目了，过滤才算结束
                }
            }
        }
        return s;
    }

    final class RequestWrapper extends HttpServletRequestWrapper {

        public RequestWrapper(HttpServletRequest servletRequest) {
            super(servletRequest);
        }

        /**
         * 
         */
        public String getHeader(String name) {
            String value = super.getHeader(name);
            if (value == null) {
                return null;
            }
            return cleanXSS(value);

        }
    }
}